package org.wu.framework.lazy.orm.database.jpa.repository.support;


import org.wu.framework.core.exception.RuntimeExceptionFactory;
import org.wu.framework.lazy.orm.database.jpa.repository.LazyJpaRepository;
import org.wu.framework.lazy.orm.database.jpa.repository.LazyRepository;
import org.wu.framework.lazy.orm.database.jpa.repository.core.DefaultLazyJapRepositoryMetadata;
import org.wu.framework.lazy.orm.database.jpa.repository.core.DefaultLazyJpaEntityMetadata;
import org.wu.framework.lazy.orm.database.jpa.repository.core.LazyJpaEntityMetadata;
import org.wu.framework.lazy.orm.database.jpa.repository.proxy.LazyJpaRepositoryProxy;
import org.wu.framework.lazy.orm.database.lambda.stream.lambda.LazyLambdaStream;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.concurrent.ConcurrentHashMap;

public final class  LazyRepositoryFactorySupport {

    /**
     * repository 缓存信息
     */
    private final static ConcurrentHashMap<Class<?>, LazyJpaEntityMetadata<?, ?, ?>> cacheLazyJpaMetadata = new ConcurrentHashMap<>();

    /**
     * 创建 jpaRepository
     * @param lazyLambdaStream  LazyLambdaStream
     * @param lazyJpaRepositoryClass repository 对象
     * @return LazyJpaRepository<T, ID>
     */
    public static <R extends LazyJpaRepository<?, ?>> R createLazyJpaRepository(LazyLambdaStream lazyLambdaStream, Class<?> lazyJpaRepositoryClass) {

        // 获取 范型 T ID
        LazyJpaEntityMetadata<?, ?, ?> lazyJpaEntityMetadata = getJpaMetadata(lazyJpaRepositoryClass);
        Class<?> entityClass = lazyJpaEntityMetadata.getEntityClass();
        Class<?> idClass = lazyJpaEntityMetadata.getIdClass();
        SimpleLazyJpaRepository<?, ?> simpleLazyJpaRepository = new SimpleLazyJpaRepository<>(lazyLambdaStream, entityClass);


        // 创建代理对象

        DefaultLazyJapRepositoryMetadata defaultLazyJapRepositoryMetadata = new DefaultLazyJapRepositoryMetadata(lazyJpaEntityMetadata, simpleLazyJpaRepository, lazyLambdaStream);
        LazyJpaRepositoryProxy lazyJpaRepositoryProxy = new LazyJpaRepositoryProxy(defaultLazyJapRepositoryMetadata);

        return (R) Proxy.newProxyInstance(lazyJpaRepositoryClass.getClassLoader(), new Class[]{lazyJpaRepositoryClass}, lazyJpaRepositoryProxy);

    }

    /**
     * 获取 jpa仓库信息
     * @param lazyJpaRepositoryClass 仓库class
     * @return jap仓库信息
     * @param <T> 实体范型
     * @param <ID> 主键范型
     * @param <R> 仓库对象
     */

    public static  <T, ID, R extends LazyJpaRepository<T, ID>> LazyJpaEntityMetadata getJpaMetadata(Class<?> lazyJpaRepositoryClass) {
        if (cacheLazyJpaMetadata.containsKey(lazyJpaRepositoryClass)) {
            return cacheLazyJpaMetadata.get(lazyJpaRepositoryClass);
        }
        Type[] genericInterfaces = lazyJpaRepositoryClass.getGenericInterfaces();
        DefaultLazyJpaEntityMetadata<?, ?, ?> defaultLazyJpaEntityMetadata = null;
        for (Type genericInterface : genericInterfaces) {
            if (genericInterface instanceof ParameterizedType parameterizedType) {
                Type rawType = parameterizedType.getRawType();
                if (LazyRepository.class.isAssignableFrom((Class<?>) rawType)) {
                    // this can get the entity and ID info
                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                    Class<?> entityClass = (Class<?>) actualTypeArguments[0];
                    Class<?> idClass = (Class<?>) actualTypeArguments[1];
                    defaultLazyJpaEntityMetadata = new DefaultLazyJpaEntityMetadata<>(entityClass, idClass, lazyJpaRepositoryClass);
                    cacheLazyJpaMetadata.put(lazyJpaRepositoryClass, defaultLazyJpaEntityMetadata);
                    break;
                }
            }
        }
        if (defaultLazyJpaEntityMetadata == null) {
            RuntimeExceptionFactory.of("无法获取:" + lazyJpaRepositoryClass.getName() + "中的范型");
        }
        return cacheLazyJpaMetadata.get(lazyJpaRepositoryClass);
    }


}
